Le carnet On est
Annale · session normale

Examen TAD 2024 — 2025

Format à trois étages : QCM dense (8 questions), questions de réflexion courtes, et un gros problème PL/SQL + BDDR sur des locations de véhicules. C'est l'annale la plus récente — patterns à connaître par cœur.

2h · ING2 GIA QCM 4 pts · Réflexion 4 pts · Problème 12 pts Aucun document autorisé

1. Le sujet

📥 Télécharger  ·  ↗ Ouvrir en plein écran

2. Notions mobilisées

PartieQuestionNotion principaleChapitre
QCM1, 7Index B-tree vs Bitmap, sélectivitéCM2
2, 6Performance d'une requête, plan d'exécutionCM2 · plan d'exécution non détaillé
3Rôles prédéfinis OracleCM1
4Définition d'une transactionCM3
5VM — REFRESH ON COMMIT vs ON DEMANDCM1
8PL/SQL — bloc, exceptions, curseurs, RAISECM5 · CM6
— · —
— · —
Réflexion1Avantages des rôlesCM1
2Tablespace vs tableCM2
3VM vs vue simple, rafraîchissementCM1
4Stratégies de fragmentation BDDRCM4
5Quand mettre en place un clusterCM2
ProblèmeA.1 à A.5Triggers, procédures, fonctions, curseurs, exceptionsCM5 · CM6
B.1, B.2BDDR — fragmentation H/V, réplication, DB linkCM4

3. Correction — QCM (4 points)

Vue d'ensemble des 8 réponses, puis détail justifié sous chaque accordéon. Chaque énoncé est cité littéralement.

SujetRéponse
1Index Bitmap adaptés pour…a) peu de valeurs distinctes
2Facteur impactant la performance d'une requêtea), d) (b) annoncé mais non détaillé
3Rôles prédéfinis Oraclea) DBA, b) CONNECT, d) RESOURCE
4Affirmation vraie sur transactionsb) (et a) également valide)
5REFRESH ON COMMIT vs ON DEMANDb) et c)
6EXPLAIN PLANhors programme — voir détail
7Index pour table factures 20k MAJ/mina) B-tree sur num_facture
8PL/SQL — affirmations correctesa), c), e)
QCM 1 — Les index Bitmap sont particulièrement adaptés pour…

QCM · 1 Les index Bitmap sont particulièrement adaptés pour :
a) Des colonnes avec peu de valeurs distinctes · b) Des colonnes fortement mises à jour · c) Des requêtes OLTP avec un grand nombre d'inserts · d) Des tables stockant des images et documents volumineux

Réponse : a) — Selon le CM2, le bitmap se met en place quand les trois conditions sont réunies :

  1. Faible sélectivité des colonnes (peu de valeurs distinctes)
  2. Beaucoup de lignes dans la table
  3. Très peu d'activités de mise à jour

b) et c) contredisent la condition 3 (MAJ d'une ligne ⇒ reconstruction totale du bitmap). d) n'est pas couvert par le cours.

QCM 2 — Quel facteur impacte directement la performance d'une requête SQL ?

QCM · 2 Quel facteur impacte directement la performance d'une requête SQL ? (Plusieurs réponses possibles)
a) L'utilisation d'index appropriés · b) La structure du plan d'exécution · c) Le nombre d'arguments dans une fonction PL/SQL · d) La fragmentation de la table

Réponses : a), b), d)

  • a) Vrai — CM2 : un index sur la colonne WHERE accélère la recherche.
  • b) Vrai — la structure du plan d'exécution (étudiée via EXPLAIN PLAN, cf. QCM 6) détermine si le SGBD utilise les bons index, le bon ordre de jointure, etc. L'optimisation et le plan de requêtes sont au programme du CM2.
  • d) Vrai — CM4 : la fragmentation permet des accès plus ciblés.
  • c) Faux — non lié à la performance d'une requête SQL.
QCM 3 — Quels sont les rôles prédéfinis en Oracle ?

QCM · 3 Quels sont les rôles prédéfinis en Oracle ? (Plusieurs réponses possibles)
a) DBA · b) CONNECT · c) SYSTEM · d) RESOURCE

Réponses : a), b), d)

Le CM1 liste les rôles prédéfinis Oracle : CONNECT, RESOURCE, DBA, EXP_FULL_DATABASE, IMP_FULL_DATABASE. c) SYSTEM est un utilisateur d'administration (le cours dit « à la création d'une base, deux rôles d'administration sont définis : SYSTEM et SYS », mais ce sont des comptes/utilisateurs, pas des rôles prédéfinis du même type que CONNECT/RESOURCE/DBA).

QCM 4 — Quelle affirmation est vraie concernant les transactions ?

QCM · 4 Quelle affirmation est vraie concernant les transactions ?
a) Une transaction commence automatiquement après un COMMIT · b) Une transaction est un ensemble d'opérations traitées comme une seule unité · c) ROLLBACK valide les modifications · d) SAVEPOINT termine la transaction

Réponse : b)

  • b) Définition canonique — CM3 : « une transaction est un ensemble ordonné d'opérations modifiant des données qu'un SGBD effectuera parfaitement et complètement, ou pas du tout ».
  • a) Faux — c'est l'inverse : une nouvelle transaction commence après un COMMIT précédent (ou un ROLLBACK), pas que COMMIT en démarre une.
  • c) Faux — ROLLBACK annule, c'est COMMIT qui valide.
  • d) Faux — SAVEPOINT pose un jalon, il ne termine pas la transaction.
QCM 5 — Différence entre REFRESH ON COMMIT et REFRESH ON DEMAND ?

QCM · 5 Quelle est la principale différence entre une vue matérialisée avec REFRESH ON COMMIT et REFRESH ON DEMAND ?
a) REFRESH ON COMMIT met à jour la vue manuellement · b) REFRESH ON COMMIT met automatiquement à jour la vue lorsqu'une modification est effectuée sur les tables sous-jacentes · c) REFRESH ON DEMAND nécessite une mise à jour manuelle avec DBMS_MVIEW.REFRESH · d) REFRESH ON DEMAND est uniquement utilisable avec les tables temporaires

Réponse : c)

Selon le CM1 :

  • c) VraiON DEMAND (défaut) : rafraîchissement manuel via DBMS_MVIEW.REFRESH('vm'). C'est la principale différence qu'on cherche à identifier.
  • b) Décrit correctement ON COMMIT mais l'énoncé demande une seule différence ; la formulation la plus discriminante est celle de la version ON DEMAND (c).
  • a) Inverse les rôles. d) Faux — pas de lien avec les tables temporaires.
QCM 6 — À quoi sert la commande EXPLAIN PLAN en SQL ?

QCM · 6 À quoi sert la commande EXPLAIN PLAN en SQL ?
a) Insérer un plan d'exécution dans la base · b) Afficher le résultat d'une requête · c) Analyser et afficher le plan d'exécution d'une requête · d) Exécuter une requête plus rapidement

Réponse : c)

  • c) VraiEXPLAIN PLAN sert à analyser et afficher le plan d'exécution d'une requête : le SGBD montre quels index seront utilisés, l'ordre des jointures, les opérations de tri/hash, etc. C'est un outil de diagnostic de performance, pas d'exécution.
  • a) Faux — la commande n'insère rien, elle affiche un plan (qui peut éventuellement être stocké dans la table PLAN_TABLE).
  • b) Faux — pour afficher le résultat d'une requête, c'est simplement SELECT.
  • d) Faux — EXPLAIN PLAN ne modifie rien à la vitesse d'exécution ; elle aide l'humain à comprendre pourquoi une requête est lente pour mieux l'optimiser ensuite (ajout d'index, réécriture, hint…).
QCM 7 — Quel index sur une table de factures à fort trafic ?

QCM · 7 Une table contenant des factures subit 20 000 modifications et plusieurs milliers d'interrogations par minute. Sans plus d'informations détaillées sur les requêtes, quels types d'index pourraient être les plus adaptés ?
a) B-tree sur num_facture · b) bitmap sur total · c) B-tree sur tva · d) bitmap sur num_facture · e) bitmap sur tva · f) B-tree sur total · g) aucune réponse correcte

Réponses : a) + f) + e)

Selon le CM2, les types d'index conseillés selon la sélectivité de la colonne :

  • f) B-tree sur totalindiscutable. total est un montant à très forte cardinalité (presque unique par facture), donc une excellente colonne pour un B-tree (rapide en lookup et en plages BETWEEN).
  • a) B-tree sur num_factureacceptée. num_facture est la clé primaire, donc bénéficie déjà d'un index naturel implicite (PK = index unique). Acceptable comme réponse formelle, même si redondante en pratique.
  • e) Bitmap sur tvadiscutable mais acceptable. tva est très peu cardinale (3-4 valeurs : 5,5% / 10% / 20% / exemption) → terrain typique du bitmap. Le bémol : 20 000 modifications/min font souffrir le bitmap (« MAJ d'une ligne ⇒ reconstruction du bitmap »). Acceptable si on considère le bitmap comme la structure naturelle pour ce type de colonne.
  • b) Bitmap sur total — Faux. Total est à très forte cardinalité, bitmap inadapté.
  • c) B-tree sur tva — Faux. B-tree sur faible cardinalité = peu efficace.
  • d) Bitmap sur num_facture — Faux. Bitmap sur clé primaire (cardinalité maximale) = pire choix possible.
QCM 8 — À propos du langage PL/SQL, quelles affirmations sont correctes ?

QCM · 8 a) Un bloc PL/SQL se compose des sections DECLARE, BEGIN, EXCEPTION et END · b) Les exceptions personnalisées ne peuvent pas être définies · c) Les curseurs explicites doivent être ouverts, traités, puis fermés manuellement · d) Une procédure stockée peut retourner une valeur comme une fonction · e) Le mot-clé RAISE permet de déclencher une exception

Réponses : a), c), e)

  • a) VraiCM5 : DECLARE / BEGIN / EXCEPTION / END;.
  • b) FauxCM6 : exceptions perso définissables avec PRAGMA EXCEPTION_INIT.
  • c) VraiCM6 : curseur explicite = OPEN / FETCH / CLOSE.
  • d) Faux — la fonction retourne une valeur, pas la procédure.
  • e) VraiRAISE e; déclenche une exception.

4. Correction — questions de réflexion (4 pts)

Réflexion 1 — Pourquoi des rôles plutôt que des droits directs ?

Réflexion · 1 Pourquoi est-il recommandé d'utiliser des rôles plutôt que d'attribuer directement des droits aux utilisateurs ?

Selon le CM1, un rôle est un ensemble nommé de privilèges. Trois avantages :

  • Maintenance simplifiée : un nouvel utilisateur du profil X reçoit le rôle X en un seul GRANT. Sans rôles, on devrait répéter chaque privilège individuellement.
  • Cohérence des permissions : tous les utilisateurs d'un même profil héritent exactement du même ensemble de droits.
  • Réversibilité : REVOKE role FROM user retire d'un coup tout le bloc, sans toucher aux privilèges directs.

Réflexion 2 — Différence tablespace / table

Réflexion · 2 Quelle est la différence entre un tablespace et une table en base de données ?

Tablespace Conteneur logique du niveau physique de l'architecture SPARC. Composé de fichiers contenant des segments. C'est un espace de stockage, configurable sur un utilisateur (DEFAULT TABLESPACE, TEMPORARY TABLESPACE).
Table Objet utilisateur / relation, dont les données vivent dans un segment de données à l'intérieur d'un tablespace. Une table a une structure (colonnes, types, contraintes). Un tablespace en est dépourvu.

Hiérarchie complète (CM2) : Base → Tablespace → Fichier → Segment → Extension → Bloc.

Réflexion 3 — Vue matérialisée et rafraîchissement

Réflexion · 3 Expliquez dans quel cas une vue matérialisée est plus performante qu'une vue simple et comment gérer son rafraîchissement de manière efficace dans un environnement transactionnel.

Cas où la VM gagne — La vue logique ré-exécute la requête à chaque appel. La VM stocke le résultat physiquement. Selon le CM1, c'est « un gain de performance sur les requêtes compliquées avec jointures » ou agrégations coûteuses : le résultat est déjà calculé.

Surtout, la VM devient nettement supérieure quand les données sont très demandées : si la même requête lourde (jointures, agrégats, sous-requêtes) est interrogée des milliers de fois pour quelques modifications sources, on amortit largement le coût du rafraîchissement. À l'inverse, sur des données peu lues mais souvent modifiées, la vue logique reste préférable.

Stratégies de rafraîchissement :

ModeMéthodeUsage transactionnel
ON DEMAND (défaut)FAST / COMPLETE / FORCERafraîchissement manuel via DBMS_MVIEW.REFRESH. Idéal si pas besoin de temps réel.
ON COMMITidemCohérence à chaque commit, coûteux. Combiner avec FAST + materialized view log pour propager seulement les changements.
START WITH … NEXTidemIntervalle régulier, compromis entre les deux.

En environnement transactionnel intensif, la combinaison REFRESH FAST + ON COMMIT avec MATERIALIZED VIEW LOG sur les sources est le meilleur compromis.

Réflexion 4 — Stratégies de fragmentation BDDR

Réflexion · 4 Quelles sont les principales stratégies pour la fragmentation des données dans une base distribuée ?

Le CM4 distingue les stratégies suivantes :

  • Horizontale (σ) — répartition des lignes. σ(R; Att = vAttᵢ) par site. Recomposition par UNION. Exemple : Client1 = σ Ville=Paris (Client).
  • Verticale (π) — répartition des attributs. La clé doit être présente dans chaque fragment. Recomposition par JOINTURE sur la clé.
  • Mixte — projection puis sélection : on découpe verticalement, puis chaque fragment vertical est découpé horizontalement.
  • Réplication — la table (ou un fragment) est copiée à l'identique sur plusieurs sites. Améliore les performances en lecture et la disponibilité (tolérance aux pannes), au prix d'un coût de synchronisation lors des écritures. Souvent utilisée pour les tables de référence peu modifiées.

Réflexion 5 — Quand mettre en place un cluster ?

Réflexion · 5 Quand peut-on décider de la mise en place d'un cluster ?

On décide d'un cluster lorsqu'on a une relation Maître–Détails (associations (1,1)–(1,n) typiques : Facture↔Client, LigneCommande↔Commande) et qu'on fait souvent des requêtes de jointure naturelle entre les deux tables.

Le cluster colocalise sur disque les lignes maître et détails partageant la même clé : les jointures deviennent des lectures séquentielles au lieu d'allers-retours aléatoires. Selon le CM2 : le cluster remplace le tablespace et requiert un index obligatoire sur les colonnes communes (CREATE INDEX … ON CLUSTER nom_cluster;) sans lequel aucune opération n'est possible.

5. Problème — Partie A : PL/SQL

Modèle Base centralisée. Tables : Client, Vehicule, Agence, Location(no_location, date_debut, date_fin, montant_total, statut, no_client, no_agence), Vehicule_Location, Facture(no_facture, date_facture, montant, paye, no_location), Cumul_Depenses_Client(no_client, annee, montant_total).

A.1 — Trigger gérant la clé de la location (1 pt)

A · 1 Écrire un trigger qui gère la clé de la location lors de sa création. On suppose qu'une séquence LocID existe.

Pattern auto-incrément (CM5) : BEFORE INSERT + assignation :new.<clé> via la séquence.

CREATE OR REPLACE TRIGGER trig_id_location
BEFORE INSERT ON Location
FOR EACH ROW
BEGIN
   :new.no_location := LocID.NEXTVAL;
END;

A.2 — Trigger vérifiant le permis du client (2 pts)

A · 2 Écrire un trigger qui vérifie qu'un client possède un permis de conduire valide avant de lui attribuer une location.

Garde-fou classique (CM5) : BEFORE INSERT + RAISE_APPLICATION_ERROR dans la plage [-20999, -20000]. Hypothèse : « permis valide » signifie Client.permis_conduire non nul (le sujet ne précise pas la sémantique).

CREATE OR REPLACE TRIGGER trig_check_permis
BEFORE INSERT ON Location
FOR EACH ROW
DECLARE
   v_permis Client.permis_conduire%TYPE;
BEGIN
   SELECT permis_conduire INTO v_permis
   FROM Client
   WHERE no_client = :new.no_client;

   IF v_permis IS NULL THEN
      RAISE_APPLICATION_ERROR(-20100,
         'Le client ne possede pas de permis de conduire valide');
   END IF;
EXCEPTION
   WHEN NO_DATA_FOUND THEN
      RAISE_APPLICATION_ERROR(-20101, 'Client inconnu');
END;

A.3 — Procédure d'ajout d'un véhicule à une location (2 pts)

A · 3 Écrire une procédure qui permet d'ajouter un véhicule à une location existante. Cette procédure reçoit le numéro de location et le numéro du véhicule.

Démarche du prof Procédure défensive qui vérifie toute l'intégrité métier avant d'insérer : (1) le véhicule existe (sinon NO_DATA_FOUND attrapé en bas), (2) la location existe et est en cours, (3) le véhicule est libre (pas déjà loué sur une autre location active). Les vérifications passent par des SELECT … FROM … JOIN … ON … du CM6. Un seul bloc EXCEPTION WHEN NO_DATA_FOUND en bas attrape tout véhicule/location inexistant.
CREATE OR REPLACE PROCEDURE affecterVehicule(
   loc NUMBER, veh NUMBER)
IS
   loc_stat Location.statut%TYPE;
   v_dummy  Vehicule.no_vehicule%TYPE;
   cpt      NUMBER;
BEGIN
   -- 1) Le vehicule existe-t-il ? (NO_DATA_FOUND sinon)
   SELECT no_vehicule INTO v_dummy
   FROM Vehicule
   WHERE no_vehicule = veh;

   -- 2) La location existe-t-elle et est-elle en cours ?
   SELECT statut INTO loc_stat
   FROM Location
   WHERE no_location = loc;

   IF loc_stat != 'en cours' THEN
      RAISE_APPLICATION_ERROR(-20004, 'location terminee');
   END IF;

   -- 3) Le vehicule est-il libre ?
   SELECT COUNT(*) INTO cpt
   FROM Location l
   JOIN Vehicule_Location vl ON l.no_location = vl.no_location
   WHERE vl.no_vehicule = veh
     AND l.statut = 'en cours';

   IF cpt > 0 THEN
      RAISE_APPLICATION_ERROR(-20005, 'vehicule non libre');
   END IF;

   -- 4) Tout est integre, on attache le vehicule a la location
   INSERT INTO Vehicule_Location(no_location, no_vehicule)
   VALUES (loc, veh);
EXCEPTION
   WHEN NO_DATA_FOUND THEN
      RAISE_APPLICATION_ERROR(-20003,
         'vehicule ou location non existant');
END;

Style « prof » : noms courts (loc, veh), pas de préfixe IN (implicite), un seul bloc EXCEPTION tout en bas qui attrape NO_DATA_FOUND pour les deux SELECT INTO qui peuvent échouer (véhicule ou location inexistants). Note de bas : les notes manuscrites du prof s'arrêtaient avant le INSERT final — on l'ajoute ici pour que la procédure ait du sens (sans cet INSERT, on a juste un valideur).

A.4 — Fonction affichant les n-ième et (n+1)-ième clients (2 pts)

A · 4 Écrire une fonction qui reçoit un entier n et affiche le n-ième et le (n+1)-ième client ayant loué le plus de véhicules dans l'année en cours.

Démarche du prof Fonction qui retourne un VARCHAR2, curseur sur les clients triés par nombre de locations décroissant, on garde uniquement les rangs n et n+1. Notes du prof : LIMIT n+1 dans le curseur (syntaxe MySQL/PG — équivalent Oracle = FETCH FIRST n+1 ROWS ONLY).
CREATE OR REPLACE FUNCTION topClient(n INT)
RETURN VARCHAR2
IS
   result VARCHAR2(500) := '';
   cpt    NUMBER := 1;
   CURSOR listClient IS
      SELECT c.no_client, c.nom, c.prenom,
             COUNT(*) AS nbrloc
      FROM Client c
      JOIN Location l ON c.no_client = l.no_client
      GROUP BY c.no_client, c.nom, c.prenom
      ORDER BY nbrloc DESC
      FETCH FIRST n + 1 ROWS ONLY;
BEGIN
   FOR c IN listClient LOOP
      IF cpt = n OR cpt = n + 1 THEN
         result := result || c.nom || ' ' || c.prenom
                   || ' (' || c.nbrloc || ') ';
      END IF;
      cpt := cpt + 1;
   END LOOP;
   RETURN result;
END;
Écarts avec l'énoncé strict Le sujet précise « dans l'année en cours » et « ayant loué le plus de véhicules ». La version du prof ne filtre pas l'année et compte des locations (et pas des véhicules). Variantes plus rigoureuses si on veut être exact :
  • Ajouter WHERE TO_CHAR(l.date_debut, 'YYYY') = TO_CHAR(SYSDATE, 'YYYY') dans le curseur.
  • Joindre Vehicule_Location et compter COUNT(vl.no_vehicule) au lieu de COUNT(*).

A.5 — Trigger sur Cumul_Depenses_Client (2 pts)

A · 5 Pourquoi doit-on associer un trigger à la gestion de la table Cumul_Depenses_Client ? Écrivez ce trigger.

Justification — La table Cumul_Depenses_Client(no_client, annee, montant_total) est un cumul agrégé. Elle doit rester cohérente avec les écritures dans Facture : à chaque nouvelle facture, le cumul correspondant doit être incrémenté. Sans trigger, on dépend des applicatifs pour faire ce UPDATE, et un oubli mène à une incohérence permanente — c'est exactement le cas d'usage d'un trigger de cohérence côté base (CM5).

CREATE OR REPLACE TRIGGER trig_maj_cumul_depenses
AFTER INSERT ON Facture
FOR EACH ROW
DECLARE
   v_no_client Location.no_client%TYPE;
   v_annee NUMBER;
   v_existe NUMBER;
BEGIN
   -- Recuperer le client a partir de la location liee
   SELECT no_client INTO v_no_client
   FROM Location
   WHERE no_location = :new.no_location;

   v_annee := TO_NUMBER(TO_CHAR(:new.date_facture, 'YYYY'));

   -- Existe-t-il deja une ligne pour ce client + annee ?
   SELECT COUNT(*) INTO v_existe
   FROM Cumul_Depenses_Client
   WHERE no_client = v_no_client AND annee = v_annee;

   IF v_existe = 0 THEN
      INSERT INTO Cumul_Depenses_Client(no_client, annee, montant_total)
      VALUES (v_no_client, v_annee, :new.montant);
   ELSE
      UPDATE Cumul_Depenses_Client
      SET montant_total = montant_total + :new.montant
      WHERE no_client = v_no_client AND annee = v_annee;
   END IF;
END;

AFTER INSERT car on agit après confirmation de la facture. FOR EACH ROW pour accéder à :new.

6. Problème — Partie B : BDDR

B.1 — Modèle réparti sur les agences (2 pts)

B · 1 Proposer un modèle de bases de données réparties sur différentes agences de location (exemples : Paris, Marseille, Lyon) en prenant en compte la répartition verticale et horizontale définies dans les règles de gestion. Justifier vos choix.

Démarche du prof Le prof a dessiné deux côtésSiège et Agences — en écrivant le MLD stocké de chaque côté. Puis pour chaque table dont on a besoin en lecture sur l'autre site, il crée soit une vue matérialisée (quand la table varie peu et est lue souvent), soit une vue simple (quand la table est rarement consultée depuis l'autre site).

Allocation des tables (MLD par site) :

SiteTables stockées localementJustification
Siège Client · Facture Centralisation : confidentialité (données personnelles), cohérence comptable.
Agence i
(Paris, Marseille, Lyon…)
Location · Vehicule · Vehicule_Location · Cumul_Depenses_Client Fragmentation horizontale sur no_agence : chaque agence ne stocke que ses lignes. Trafic local prédominant.

a) Côté agence — accéder aux clients (au siège)

Une agence a constamment besoin de noclient + permis pour enregistrer une location. La table Client varie peu, et on n'a pas besoin de tous les attributs (CB, adresse…) → projection verticale répliquée en vue matérialisée :

-- Sur chaque agence : VM repliquant la projection de Client
CREATE MATERIALIZED VIEW client
REFRESH ON DEMAND            -- ON COMMIT si beaucoup de modifs cote siege
AS SELECT noclient, permis
   FROM client@SiegeLink;

ON DEMAND suffit ici : les clients changent rarement, on rafraîchit manuellement. Si le siège enregistre énormément de nouveaux clients chaque heure, on passe à ON COMMIT pour la cohérence en temps réel.

b) Côté siège — recomposer les données des agences

Le siège a parfois besoin de voir l'historique global (factures, états comptables, audits). Comme cet accès est occasionnel, on utilise des vues simples qui font l'UNION à la demande sur les fragments distants. Une exception : Vehicule bouge peu et est consultée souvent → on la réplique en VM.

-- Sur le siege : recomposer Location depuis toutes les agences
CREATE VIEW location AS
   SELECT * FROM location@agence1link
   UNION
   SELECT * FROM location@agence2link;
   -- … UNION pour chaque agence

-- Idem pour Vehicule_Location et Cumul_Depenses_Client (vues simples)
CREATE VIEW vehicule_location AS
   SELECT * FROM vehicule_location@agence1link
   UNION SELECT * FROM vehicule_location@agence2link;

CREATE VIEW cumul_depenses_client AS
   SELECT * FROM cumul_depenses_client@agence1link
   UNION SELECT * FROM cumul_depenses_client@agence2link;

-- Exception : Vehicule varie peu mais est lue souvent -> VM
CREATE MATERIALIZED VIEW vehicule
REFRESH ON DEMAND
AS SELECT * FROM vehicule@agence1link
   UNION SELECT * FROM vehicule@agence2link;

Récap du choix view simple vs VM :

Table reconstituée au siègeTypePourquoi
locationVue simpleLue rarement par le siège ; coût négligeable de faire l'UNION à la volée.
vehicule_locationVue simpleIdem.
cumul_depenses_clientVue simpleIdem.
vehiculeVM ON DEMANDDonnées peu modifiées (catalogue) mais lues souvent → on amortit en répliquant.

Justifications globales (CM4) :

  • Fragmentation horizontale de Location, Vehicule, Vehicule_Location, Cumul_Depenses_Client par agence : 80 % du trafic est local à l'agence.
  • Réplication par VM (projection (noclient, permis)) pour permettre à chaque agence de saisir des locations sans aller-retour permanent vers le siège.
  • Vue simple côté siège pour les tables consultées rarement : pas de coût de stockage/sync, on accepte la latence des UNION distants.
  • VM côté siège pour Vehicule uniquement : faible volume de modifs justifie la copie locale.

B.2 — Optimiser l'accès à la table Agence (1 pt)

B · 2 On suppose que dans la base de données de l'agence de Paris, il existe une table contenant la relation Agence. Que faut-il faire dans les bases de données des autres agences pour optimiser l'accès aux informations de cette table ?

Répliquer la table via une vue matérialisée distante. La table Agence est peu mise à jour mais lue souvent. Le CM4 recommande dans ce cas la réplication par VM : chaque autre agence stocke une copie locale rafraîchie automatiquement.
-- Prealable : DB link vers la base de Paris
CREATE DATABASE LINK db_paris
CONNECT TO user_distant IDENTIFIED BY mdp
USING 'paris_service';

-- Sur Marseille et Lyon : VM repliquant Agence
CREATE MATERIALIZED VIEW Agence_local
REFRESH FAST
AS SELECT * FROM Agence@db_paris;

Bénéfices (CM4) :

  • Disponibilité locale même en cas de réseau lent / indisponible
  • Augmentation du parallélisme en lecture
  • Diminution du coût des transmissions réseau

Compromis : cohérence seulement éventuelle (entre deux refresh), acceptable ici car les agences changent rarement.

Bilan rapide

📌 À solidifier en priorité
• Pattern auto-incrément avec séquence (A.1)
• Trigger de cumul sur Facture (A.5)
• Index B-tree vs Bitmap selon profil de la table (QCM 7)
• Différences ON COMMIT / ON DEMAND (QCM 5)
🎯 Pattern Partie A récurrent
Trigger BEFORE INSERT FOR EACH ROW pour l'auto-incrément et les garde-fous. Trigger AFTER INSERT FOR EACH ROW pour les cumuls et agrégats.